/**
 * @author Lucas Venezian Povoa <lucasvenez at gmail dot com> 
 */
function Graph() {

	var strict = false;
	
	var digraph = false;
	
	var label = null;
	
	var startNode = null;
	
	var nodes = new Array();
	
	var edges = new Array();
	
	var subgraphs = new Array();
	
	var nodeAttributes = new Array();
	
	var edgeAttributes = new Array();
	
	var attributes = new Array();
	
	this.getAllIncomingEdges = function(node) {
		
		var result = new Array();
		
		for (var i = 0; i < edges.length; i++) {
			
			
			
		}
		
		return result;
		
	};
	
	this.getAllOutgoingEdges = function(node) {
		
	};
	
	this.setStrict = function(s) {
		
		if (typeof s == "boolean" || s instanceof Boolean)
			strict = s;
		else
			throw "Invalid parameter type.";
	};
	
	this.isStrict = function() {
		return strict;
	};

	this.setDigraph = function(d) {
		
		if (typeof d == "boolean" || d instanceof Boolean)
			digraph = d;
		else
			throw "Invalid parameter type.";
	};
	
	this.isDigraph = function() {
		return digraph;
	};
	
	this.setLabel = function(i) {
		
		if (typeof i == "number" || typeof i == "boolean" || 
				i instanceof Number || i instanceof Boolean)
			label = i + "";
		
		else if (typeof i == "string" || i instanceof String)
			label = i;
		
		else
			throw "Invalid parameter type.";
		
	};
	
	this.getLabel = function() {
		return label;
	};
	
	this.setStartNode = function(node) {
		
		if (node instanceof Node)
			startNode = node;
		else if (node instanceof Graph)
			startNode = node.getStartNode();
		else
			throw "Invalid paramter type.";
	};
	
	this.getStartNode = function() {
		return startNode;
	};
	
	this.addNode = function(node) {
		
		if (node instanceof Node)
			nodes.concat([node]);
		else
			throw "Invalid parameter type.";
	};
	
	this.hasNode = function(node) {
		
		var result = false;
		
		for (var i = 0; i < nodes.length && !result; i++)
			result |= nodes[i].equals(node);
		
		return result;
	};
	
	this.getNodes = function() {
		return nodes;
	};
	
	this.getNode = function(index) {
		
		var result = null;
		
		if (nodes.length > index && index > -1)
			result = nodes[index];
		else
			throw "Index out of bound exception.";
		
		return result;
	};
	
	this.removeNode = function(index) {
		
		if (index instanceof Number || typeof index == "number")
			nodes.splice(index, 1);
		
		else if (index instanceof Node) {
			for (var i = 0; i < nodes.length; i++)
				if (nodes[i].equals(node))
					nodes.splice(i, 1);
		
		} else
			throw "Invalid parameter type.";
	};
	
	this.addSubgraph = function(graph) {
		
	};
	
	this.getSubgraphs = function() {
		
	};
	
	this.addEdge = function(edge) {
		
		if (edge instanceof Edge)
			edges.concat([edge]);
		else
			throw "Invalid parameter type.";
	};
	
	this.hasEdge = function(edge) {
		
		if (edge instanceof Edge) {
			var result = false;
		
			for (var i = 0; i < edges.length && !result; i++)
				result |= edges[i].equals(node);
		
			return result;
		} else
			throw "Invalid parameter type.";
	};
	
	this.getEdges = function() {
		return edges;
	};
	
	this.getEdge = function(index) {
		
		var result = null;
		
		if (edges.length > index && index > -1)
			result = edges[index];
		else
			throw "Index out of bound.";
		
		return result;
	};
	
	this.removeEdge = function(index) {
		
		if (index instanceof Number || typeof index == "number")
			edge.splice(index, 1);
		
		else if (index instanceof Edge) {
			for (var i = 0; i < edges.length; i++)
				if (edges[i].equals(node))
					edges.splice(i, 1);
		
		} else
			throw "Invalid parameter type.";
	};
	
	this.addNodeAttribute = function(key, value) {
		nodeAttributes[key] = value;
	};
	
	this.removeNodeAttribute = function(key) {
		nodeAttributes[key] = undefined;
	};
	
	this.hasNodeAttribute = function(key) {
		return nodeAttributes[key] != undefined;
	};
	
	this.hasNodeAttributeValue = function(value) {
		
		var result = false;
		
		for (var i = 0; i < nodeAttributes.length && !result; i++)
			result |= nodeAttributes[i] == value;
		
		return result;
	};
	
	this.getNodeAttribute = function(key) {
		
		var result = null;
		
		if ((result = nodeAttributes[key]) != undefined)
			return result;
		else
			return null;
	};
	
	this.addEdgeAttribute = function(key, value) {
		edgeAttributes[key] = value;
	};
	
	this.removeEdgeAttribute = function(key) {
		
		var result = edgeAttributes[key];
		
		edgeAttributes[key] = undefined;
		
		if (result != undefined)
			return result;
		else
			return null;
	};
	
	this.hasEdgeAttribute = function(key) {
		return edgeAttributes[key] != undefined;
	};
	
	this.hasEdgeAttributeValue = function(value) {
		
		var result = false;
		
		for (var i = 0; i < edgeAttributes.length && !result; i++)
			result |= edgeAttributes[i] == value;
		
		return result;
	};
	
	this.getEdgeAttribute = function(key) {
		
		var result = null;
		
		if ((result = edgeAttributes[key]) != undefined)
			return result;
		else
			return null;
	};
	
	this.addAttribute = function(key, value) {
		attributes[key] = value;
	};
	
	this.removeAttribute = function(key) {
		
		var result = attributes[key];
		
		attributes[key] = undefined;
		
		if (result != undefined)
			return result;
		else
			return null;
	};
	
	this.hasAttribute = function(key) {
		return attributes[key] != undefined;
	};
	
	this.hasAttributeValue = function(value) {
		var result = false;
		
		for (var i = 0; i < attributes.length && !result; i++)
			result |= attributes[i] == value;
	};
	
	this.getAttribute = function(key) {
		var result = null;
		
		if ((result = attributes[key]) != undefined)
			return result;
		else
			return null;
	};
}